import asyncio
import itertools
import sys
import warnings

warnings.filterwarnings("ignore", category=DeprecationWarning)


# 打算交给 asyncio 处理的协程要使用 @asyncio.coroutine 装饰
@asyncio.coroutine
def spin(msg):
    write, flush = sys.stdout.write, sys.stdout.flush
    for char in itertools.cycle('|/-\\'):
        status = char + ' ' + msg
        write(status)
        flush()
        write('\x08' * len(status))
        try:
            yield from asyncio.sleep(.1)
        except asyncio.CancelledError:
            break
    write(' ' * len(status) + '\x08' * len(status))


@asyncio.coroutine
def slow_function():
    # 把控制权交给主循环，在休眠结束后恢复这个协程
    yield from asyncio.sleep(3)
    return 42


@asyncio.coroutine
def supervisor():
    asy = getattr(asyncio, 'ensure_future')
    # 排定 spin 协程的运行时间，使用一个Task 对象包装 spin 协程，并立即返回
    spinner = asy(spin('thinking!'))
    print('spinner object:', spinner)
    # 驱动 slow_function() 函数
    result = yield from slow_function()
    spinner.cancel()  # 取消 会在协程当前暂停的yield处抛出asyncio.CancelledError 异常
    return result


def main():
    loop = asyncio.get_event_loop()  # 获取事件循环的引用
    # 驱动 supervisor 协程，让它运行完毕；这个协程的返回值是这次调用的返回值
    result = loop.run_until_complete(supervisor())
    loop.close()
    print('Answer:', result)


if __name__ == '__main__':
    main()
